package shakespeare;

import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import com.swabunga.spell.engine.SpellDictionary;
import com.swabunga.spell.engine.SpellDictionaryHashMap;
import com.swabunga.spell.event.SpellCheckEvent;
import com.swabunga.spell.event.SpellCheckListener;
import com.swabunga.spell.event.SpellChecker;
import com.swabunga.spell.event.StringWordTokenizer;

public class ShakespeareMain {
	private static ArrayList<String> filelist = new ArrayList<>();
	private static ArrayList<Double> fileddlist = new ArrayList<>();
	private static ArrayList<ArrayList<WordEntity>> filewordslist = new ArrayList<>();
	private static ArrayList<String> wordslist = new ArrayList<>();
	private static ArrayList<HashMap<String, ArrayList<String>>> wordsInvertedIndex = new ArrayList<>();
	private static String q;
	private static ArrayList<WordEntity> qarr = new ArrayList<WordEntity>();
	private static ArrayList<String> results = new ArrayList<>();
	private static ArrayList<Double> resultsqd = new ArrayList<>();

	private static long begintime = 0;

	public static JFrame main = new JFrame("检索");
	public static JTextArea txtQuery = new JTextArea(1, 15);
	public static JTextArea txtTips = new JTextArea(1, 15);
	public static JTextArea txtResult = new JTextArea("", 12, 40);
	public static JButton btnQuery = new JButton("查询");
	public static JButton btnInit = new JButton("初始化数据");
	public static JScrollPane resultPane = new JScrollPane(txtResult,
			JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
			JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

	public static void main(String[] args) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				readfile();
			}
		});
		t.start();
		main.setSize(500, 400);
		main.setLocation(400, 400);
		main.setResizable(false);
		main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		Container mPanel = main.getContentPane();
		mPanel.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.insets = new Insets(5, 0, 0, 5);

		c.gridx = 0;
		c.gridy = 10;
		c.gridwidth = 20;
		c.gridheight = 10;
		c.fill = GridBagConstraints.VERTICAL;
		c.anchor = GridBagConstraints.CENTER;
		mPanel.add(txtQuery, c);
		c.gridx = 50;
		c.gridy = 10;
		c.gridwidth = 20;
		c.gridheight = 10;
		c.fill = GridBagConstraints.VERTICAL;
		c.anchor = GridBagConstraints.CENTER;
		mPanel.add(btnQuery, c);
		c.gridx = 100;
		c.gridy = 10;
		c.gridwidth = 20;
		c.gridheight = 10;
		c.fill = GridBagConstraints.VERTICAL;
		c.anchor = GridBagConstraints.CENTER;
		mPanel.add(btnInit, c);

		c.gridx = 0;
		c.gridy = 300;
		c.gridwidth = 140;
		c.gridheight = 10;
		c.fill = GridBagConstraints.VERTICAL;
		c.anchor = GridBagConstraints.CENTER;
		txtResult.setLineWrap(true);
		txtResult.setEditable(false);
		mPanel.add(resultPane, c);

		c.gridx = 0;
		c.gridy = 350;
		c.gridwidth = 200;
		c.gridheight = 10;
		c.fill = GridBagConstraints.VERTICAL;
		c.anchor = GridBagConstraints.CENTER;
		txtTips.setEditable(false);
		mPanel.add(txtTips, c);

		btnInit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (Shakespeare.isIniting) {
					txtTips.setText("正在初始化...");
					return;
				}
				setInitMod(true);
				Shakespeare.init();
			}
		});
		btnQuery.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				q = txtQuery.getText().trim();
				if (q.equals("")) {
					txtTips.setText("输入要查询关键字");
				}
				begintime = System.currentTimeMillis();
				initquery();
				StringBuffer sb = new StringBuffer();
				for (int i = results.size() - 1; i >= 0; i--) {
					sb.append(results.get(i) + "\n");
				}
				txtResult.setText(sb.toString());
				try {
					checkword(Shakespeare.DICT_FILE, q);
				} catch (FileNotFoundException ex) {
					ex.printStackTrace();
					txtTips.setText("词典文件未找到");
				} catch (IOException ex) {
					ex.printStackTrace();
					txtTips.setText("词典文件读取错误");
				}
			}
		});
		main.setVisible(true);
	}

	private static void checkword(String dictpath, String s)
			throws FileNotFoundException, IOException {
		SpellDictionary dictionary = new SpellDictionaryHashMap(new File(
				dictpath));
		SpellChecker spellChecker = new SpellChecker(dictionary);
		spellChecker.addSpellCheckListener(new SuggestionListener());
		spellChecker.checkSpelling(new StringWordTokenizer(s));

	}

	public static class SuggestionListener implements SpellCheckListener {

		public void spellingError(SpellCheckEvent event) {
			System.out.println("Misspelling: " + event.getInvalidWord());
			StringBuffer sb = new StringBuffer(
					ShakespeareMain.txtResult.getText());
			List suggestions = event.getSuggestions();
			if (suggestions.isEmpty()) {
				System.out.println("No suggestions found.");
			} else {
				sb.append("拼写错误:" + event.getInvalidWord());
				sb.append("拼写建议:");

				System.out.print("Suggestions: ");

				for (Iterator i = suggestions.iterator(); i.hasNext();) {
					sb.append(i.next());
					if (i.hasNext()) {
						sb.append(", ");
					}
				}
				System.out.println();
			}
			ShakespeareMain.txtResult.setText(sb.toString());
		}

	}

	private static void readfile() {
		// 读取记录文件
		try {
			BufferedReader br = new BufferedReader(new FileReader(
					Shakespeare.INPUT_FILETXT));
			String s;
			String[] arrstring;
			if ((s = br.readLine()) != null) {
				if (!s.equals(""))
					s.substring(s.length() - 1);
				arrstring = s.split(",");
				filelist.addAll(Arrays.asList(arrstring));
			}
			// System.out.println(filelist.toString());
			if ((s = br.readLine()) != null) {
				if (!s.equals(""))
					s.substring(s.length() - 1);
				arrstring = s.split(",");
				for (int i = 0; i < arrstring.length; i++) {
					if (arrstring[i].equals(""))
						continue;
					fileddlist.add(Double.parseDouble(arrstring[i]));
				}
			}
			// System.out.println(fileddlist.toString());
			if ((s = br.readLine()) != null) {
				if (!s.equals(""))
					s.substring(s.length() - 1);
				arrstring = s.split(",");
				wordslist.addAll(Arrays.asList(arrstring));
			}
			// System.out.println(wordslist.toString());
			if ((s = br.readLine()) != null) {
				if (!s.equals(""))
					s.substring(s.length() - 1);
				arrstring = s.split("\\|");
				// System.out.println("arrstring.length: " + arrstring.length);
				for (String string1 : arrstring) {
					ArrayList<WordEntity> al2 = new ArrayList<>();
					if (string1.equals(""))
						continue;
					string1.substring(string1.length() - 1);
					String[] arrstring1 = string1.split(";");
					for (String string2 : arrstring1) {
						String[] as1 = string2.split(",");
						WordEntity we = new WordEntity(as1[0],
								Integer.parseInt(as1[1]),
								Integer.parseInt(as1[2]),
								Double.parseDouble(as1[3]),
								Integer.parseInt(as1[4]),
								Double.parseDouble(as1[5]),
								Double.parseDouble(as1[6]));
						al2.add(we);
					}
					filewordslist.add(al2);
				}
			}
			// System.out.println(filewordslist.toString());
			int count = 0;
			while ((s = br.readLine()) != null) {
				s.substring(s.length() - 1);
				String string1 = s;
				HashMap<String, ArrayList<String>> map = new HashMap<>();
				string1.substring(string1.length() - 1);
				String[] as1 = string1.split(",");
				ArrayList<String> al2 = new ArrayList<>();
				for (String string3 : as1) {
					al2.add(string3);
				}
				map.put(wordslist.get(count), al2);
				wordsInvertedIndex.add(map);
				count++;
			}
			// System.out.println(wordsInvertedIndex.toString());
		} catch (Exception e) {
			txtTips.setText("读取文件出错, 请尝试初始化文件");
			e.printStackTrace();
		}
	}

	private static void initquery() {
		int n = wordslist.size();

		// 初始化查询关键字, 并且根据关键字处理
		Map<String, Integer> map = new HashMap<String, Integer>();
		StringTokenizer st = new StringTokenizer(q, Shakespeare.DELIM);
		double qd = 0d;
		while (st.hasMoreTokens()) {
			String letter = st.nextToken();
			letter = letter.toLowerCase();
			// 去除一些不必要的词
			if (Shakespeare.FWORDS2.lastIndexOf(letter) != -1)
				continue;
			Shakespeare.cutword(letter);
			int count;
			if (map.get(letter) == null) {
				count = 1;
			} else {
				count = map.get(letter).intValue() + 1;
			}
			map.put(letter, count);
		}
		for (String key : map.keySet()) {
			WordEntity we = new WordEntity(key, map.get(key), map.get(key),
					1 + Math.log10(map.get(key)));
			if (wordslist.indexOf(we.getKey()) == -1) {
				we.setDf(0);
				we.setIdf(0d);
				we.setWeight(0d);
			} else {
				int df = wordsInvertedIndex.get(wordslist.indexOf(we.getKey()))
						.get(we.getKey()).size();
				we.setDf(df);
				double idf = Math.log10(n / df);
				we.setIdf(idf);
				we.setWeight(we.getTfw() * we.getIdf());
			}
			qarr.add(we);
			for (int j = 0; j < filelist.size(); j++) {
				qd = 0d;
				for (Iterator<WordEntity> it = filewordslist.get(j).iterator(); it
						.hasNext();) {
					WordEntity wef = it.next();
					if (wef.getKey().equals(key)) {
						qd += wef.getWeight() * we.getWeight();
					}
				}
				// System.out.print(" " + j);
				int t = results.lastIndexOf(filelist.get(j));
				if (qd != 0) {
					if (t == -1) {
						results.add(filelist.get(j));// 结果列表
						resultsqd.add(qd);
					} else {
						resultsqd.set(t, qd + resultsqd.get(t));
					}
				}
			}
		}
		System.out.println(results.size());
		System.out.println(resultsqd.size());
		// TODO 根据qd/dd排序
		for (int i = 0; i < results.size(); i++) {
			resultsqd.set(
					i,
					resultsqd.get(i)
							/ fileddlist.get(filelist.indexOf(results.get(i))));
		}
		heapSort(resultsqd, results, resultsqd.size());
		for (int i = 0; i < results.size(); i++) {
			System.out.println(results.get(i) + "   qd/dd:  "
					+ resultsqd.get(i));
		}
		System.out.println("time: " + (System.currentTimeMillis() - begintime)
				+ "ms");

	}

	public static void heapSort(ArrayList<Double> array, ArrayList<String> as,
			int n) {
		if (array == null) {
			throw new NullPointerException();
		}
		if (n > array.size()) {
			throw new ArrayIndexOutOfBoundsException();
		}

		buildMaxHeap(array, as, n);

		for (int i = n - 1; i >= 1; i--) {
			// swap(array, 0, i);
			Collections.swap(array, 0, i);
			Collections.swap(as, 0, i);

			maxHeapify(array, as, 0, i);
		}
	}

	public static void buildMaxHeap(ArrayList<Double> a, ArrayList<String> as,
			int n) {

		for (int i = n / 2 - 1; i >= 0; i--) {
			maxHeapify(a, as, i, n);
		}

	}

	private static void maxHeapify(ArrayList<Double> a, ArrayList<String> as,
			int i, int n) {

		int largest;

		int leftIndex = 2 * i + 1;
		int rightIndex = leftIndex + 1;

		if (leftIndex < n && a.get(leftIndex) > a.get(i)) {
			largest = leftIndex;
		} else {
			largest = i;
		}
		if (rightIndex < n && a.get(rightIndex) > a.get(largest)) {
			largest = rightIndex;
		}

		if (largest != i) {
			// swap(a, i, largest);
			Collections.swap(a, i, largest);
			Collections.swap(as, i, largest);

			maxHeapify(a, as, largest, n);
		}
	}

	/**
	 * 设置在初始化的时候,某些按钮不可点击
	 */
	public static void setInitMod(boolean isInit) {
		btnInit.setEnabled(!isInit);
		btnQuery.setEnabled(!isInit);
		if (isInit) {
			txtTips.setText("正在初始化,请稍后");
		} else {
			txtTips.setText("初始化完成!");
			Thread t = new Thread(new Runnable() {

				@Override
				public void run() {
					readfile();
				}
			});
			t.start();		}
	}
}
